Skip to content

feat(rn): 支持页面 preload 并修复预加载页面生命周期 - #2615

Open
Blackgan3 wants to merge 15 commits into
masterfrom
feat-support-rn-preload
Open

Blackgan3 wants to merge 15 commits into
masterfrom
feat-support-rn-preload

Conversation

@Blackgan3

@Blackgan3 Blackgan3 commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

新增 mpx.preload({ url }): void,允许停留在当前页面时提前创建目标页面,并通过 RN 的 onLoad 第三个参数 isPreload 标识本次是否为预加载初始化。修复预加载实例正式进入后缺失 onShow、navigation 引用未同步及 EventChannel 交接问题。

例如 A 预加载 B,再 navigateTo B 时,复用同一实例,在首次 onShow 领取正式跳转创建的 EventChannel,正式聚焦触发 onShow,onLoad 不重跑。无 getId 时沿用 React Navigation 的同名候选复用规则,正式跳转参数可能与初始化参数不同。

改动

  • 接入 preload 导出、类型、静态 canIUse 支持表与默认 Promise 黑名单;不占用导航锁,不提供完成回调或就绪 Promise。
  • RN 的 onLoad(query, decodedQuery, isPreload) 增加第三个参数,不新增实例属性;usePageStatus 中 navigation 更换仅取消事件订阅,独立卸载 cleanup 删除 pageStatus;保留原状态属性、watcher 和导航回调结构,同步页面映射和 RouteContext。
  • EventChannel 沿用现有创建与临时槽交接;普通页面在 BEFORECREATE 初始化,预加载阶段不创建通道,首次正式 onShow 领取。已有通道时直接返回,后续显示不重新匹配或替换。业务在正式进入的 onShow 中获取通道、避免重复注册,并等待接收方就绪后发送消息。
  • 提供一份简短的 preload API 说明。

@Blackgan3
Blackgan3 marked this pull request as ready for review November 9, 2026 11:42
setFocusedNavigation(navigation)
pageStatusMap[pageId] = 'show'
})
if (navigation.isFocused()) Promise.resolve().then(show)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个条件没有必要

if (navigation.isFocused && navigation.isFocused()) {
Promise.resolve().then(() => {
const show = () => {
if (navigation.isFocused()) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

navigation.isFocused的判断还需要保留

const { navigation, route } = props
const currentPageId = useMemo(() => ++pageId, [])
const routeContextValRef = useRef({ navigation, pageId: currentPageId })
const routeContextValue = useMemo(() => ({ navigation, pageId: currentPageId }), [navigation, currentPageId])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

navigation会更新么?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

即使会更新也直接修改ref的值即可,不需要创建新的context触发订阅刷新

const { navigation, route } = props
const currentPageId = useMemo(() => ++pageId, [])
const routeContextValRef = useRef({ navigation, pageId: currentPageId })
const routeContextValue = useMemo(() => ({ navigation, pageId: currentPageId }), [navigation, currentPageId])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

即使会更新也直接修改ref的值即可,不需要创建新的context触发订阅刷新


if (type === 'page') {
const props = propsRef.current
const wasPreloaded = !!props.navigation.getState?.()?.preloadedRoutes?.some(route => route.key === props.route.key)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

作为onLoad的第三个参数 isPreload即可,不需要挂载实例属性

return () => {
unWatch && unWatch()
if (type === 'page') {
del(pageStatusMap, pageId)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为啥要在这里加这个?

@hiyuki hiyuki left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

基于 dc929c2 的评审,发现两个需要处理的问题,见行内评论。

navigation 更新及保留 pageStatus 的修改有依据:React Navigation 明确说明预加载页面正式进入时会更新 navigation。针对性测试中,实例复用、onLoad 只执行一次、首次 onShow 前领取 EventChannel 均正常。

验证:变更文件 ESLint 通过,47 项相关及针对性测试通过。针对性测试位于临时评审快照中,使用 RN mock,未进行真机验证。

return
}
const finalPath = resolvePath(path, getBasePath(navigation)).slice(1)
navigation.preload(finalPath, queryObj)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 预加载页会提前覆盖当前页的状态栏样式

调用 preload 后,目标页的 pageWrapperHOC → MpxNav 会挂载,而 MpxNav 无条件渲染 StatusBar。例如 A 配置 navigationBarTextStyle: 'white'、B 配置 'black',在 A 预加载 B 后,尚未跳转就会被 B 覆盖。针对性测试确认了未聚焦的 B 仍追加 StatusBar;RN 的状态栏属性按组件挂载顺序合并:https://reactnative.dev/docs/statusbar#usage-with-navigator 。

建议让状态栏配置随页面焦点生效,并覆盖多个预加载页面的场景。

## 注意事项 {#notes}

- 预加载会提前执行 `onLoad`,但不触发 `onShow/onHide`。正式进入并复用该页面时触发 `onShow`,不重复执行 `onLoad`。
- RN 的 `onLoad(query, decodedQuery, isPreload)` 第三个参数表示本次初始化是否发生在预加载阶段;普通打开或入栈后才初始化时为 `false`。前两个参数保持原有含义,分别为原始 query 和解码后的 query。

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] 补齐文档入口及 Skill 同步

新增 preload.md 后,还需要在 docs-vitepress/.vitepress/config.ts 的路由 API 侧边栏添加入口,并同步 .agents/skills/mpx/references/rn/rn-api-reference.md、rn-script-reference.md 及相关索引,说明 preload、onLoad 第三个参数 isPreload,以及 EventChannel 的获取时机。当前 PR 未包含这些更新,文档缺少侧边栏入口,Skill 也无法反映新增能力;这也是仓库 AGENTS.md 要求在同一次改动中同步的内容。

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants